import importlib
import inspect
from tornado.web import RequestHandler
from tornado.escape import to_unicode

from core.utils.module_utils import get_all_modules
from environment import environment


class OpenApiDecorate:
    """接口装饰器
    1. 这是一个函数装饰器
    2. 主要为装饰后的函数添加一些属性
    """

    def __init__(self, name, permisson=None) -> None:
        self.permisson = permisson
        self.name = name

    def __call__(self, original_func):
        def _api_func(*arg, **kwargs):
            return original_func(*arg, **kwargs)
        # 为函数添加一些属性
        _api_func.__handler_name__ = original_func.__name__
        _api_func.__api_name__ = self.name

        return _api_func


class openApiFactory:
    """openApi的处理工厂函数
    1. 主要封装一些open_api的处理函数
    2. 如通过api_name来获取api等
    """
    __service__ = {}  # 存储api

    @classmethod
    def execute_open_api(cls, api_name, params):
        """执行open_api的函数
        """
        # 获取执行器
        _executor = cls.get_executor(api_name)
        # 执行
        return _executor(*params)

    @classmethod
    def get_executor(cls, api_name):
        """获取api_name对应的处理器
        1. 也就是我们使用@open_api修改的函数
        """
        # 获取对应的api处理函数
        _service = cls.get_open_api_handler(api_name)
        return _service

    @classmethod
    def get_open_api_handler(cls, name):
        service = cls.__service__.get(name)
        if not service:
            print(f"位置的api{name}")
        # 获取到name对应的函数
        _class = getattr(importlib.import_module(
            service["path"]), service["service"])
        # 我们拿到类实例化之后的方法，这样可以实例化后的方法可以拿到更多的信息
        return getattr(_class(), service["handler"])  # 获取到对应的函数对象

    @classmethod
    def register_services(cls, libs):
        # 一般项目刚启动的时候，就应该调用这个函数
        _modules = []
        for _path in libs:
            _modules += get_all_modules(_path, "service", True)

        for _module, _module_path in _modules:
            # 获取到所有的类
            for _name, _class in inspect.getmembers(_module, inspect.isclass):
                # 获取到对应的模块
                if inspect.getmodule(_class) == _module:
                    # 获取这个类下的方法,方法是被装饰器修饰过的方法，且可以调用
                    for _method_name, _method_class in inspect.getmembers(
                        _class,
                        lambda _method: callable(_method) and hasattr(
                            _method, "__api_name__")
                    ):
                        # 想容器中添加api_name和对应的handler
                        cls.__service__[_method_class.__api_name__] = {
                            "name": _method_class.__api_name__,
                            "service": _name,  # 函数所在的类
                            "handler": _method_class.__handler_name__,  # 函数名
                            "path": _module_path  # 函数所在的路径
                        }


class BaseRequestHandler(RequestHandler):
    """请求的基类服务
    1. 再这里写一些请求的额外的操作的方法
    2. 使注册的路由可以处理get方法,也可以处理post方法
    """

    def __init__(self, application, request, **kwargs) -> None:
        super().__init__(application, request, **kwargs)

    @property
    def db(self):
        # 数据库操作
        return environment.db

    def get(self, *args):
        # 获取参数
        request = self.request
        context = self.get_context()
        params = {_key: to_unicode(_value) for _key, _value in list(request.arguments.items())}
                  
        # 传递参数
        result = self.execute(args, params, context)
        if result is not None:
            self.write(result)
        # 关闭连接刷新缓冲区
        self.finish()

    def post(self, *args):
        # 获取参数
        request = self.request  # 因为request中信息较多我们重这里获取相应的信息
        params = request.body
        result = self.execute(params)
        if result is not None:
            self.write(result)
        # 传递参数
        self.execute()
        # 关闭连接刷新缓冲区
        self.finish()

    def execute(self):
        pass

    def get_context(self):
        """获取上下问对象
        1. 上下文中保存着我们需要的必要的信息,比如token
        """
        return None

    def set_context(self):
        pass
